/*--------------------------------------------------------
        SNOMPUTZ	Routinen zum Filtern vom BMP-Dateien
        --------------------------------------------------------*/

#include <windows.h>
#include <windowsx.h>
#include <shellapi.h>   // f�r Drag&Drop
#include <commdlg.h>
//#include <print.h> // Nur 3.11!
//#include <ctl3d.h> // nicht MSVC 8.0
#include <commctrl.h>
//#include <bwcc.h>

#include "filebox.h"
#include "dvi.rh"
#include "dvi_win.h"

//#include <math.h>

//#define min( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )
//#define max( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )

#if !defined( WM_MOUSEWHEEL )
#define WM_MOUSEWHEEL	0x20A
#endif

/* �ffnet eine neue DVI-Datei */
SWORD open_doc( DVI_DOC *doc, LONG seite );


/* 23.12.92 */

// Ein paar Defs fehlen ...
#ifndef LPNMTTDISPINFO
#define LPNMTTDISPINFO LPTOOLTIPTEXT
#define TTN_GETDISPINFO TTN_NEEDTEXT
#endif

// Identifier f�r Tool/Statusbar
#define ID_TOOLBAR	17
#define ID_STATUSBAR 18

#define iMaxTool 10

TBBUTTON pToolbarButtons[] = {
	{ 0, MDOPEN, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0 },
//	{ 1, IDM_SAVE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0 },
	{ 2, MDDRUCKE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0 },
	{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0 },
	{ 5, MACOPYPAGE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0 },
	{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0 },
	{ 3, MAPREV, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0 },
	{ 4, MANEXT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0 },
	{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0 },
	{ 7, MAKLEIN, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0 },     // Alt: Bild 3
	{ 8, MAGROSS, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0 },     // Alt: Bild 4
};


// Einige Defines, die *nicht* in der RC-Datei ben�tigt werden!
#define CNF_MENU_POS	2
// Bitmapnamen werden an dieses Men� geh�ngt!
#define BITMAP_MENU_POS 3

#define IDM_FIRSTCHILD		4242

BOOL PASCAL InfoDlgProc( HWND hdlg, UINT message, WPARAM wParam, LONG lParam );
long PASCAL DVIWndProc( HWND hwnd, UINT message, WPARAM wParam, LONG lParam );
BOOL PASCAL CloseEnumProc( HWND hwnd, LONG lParam );
long PASCAL FrameWndProc( HWND hwnd, UINT message, WPARAM wParam, LONG lParam );


// Parameterdatei(en) finden
void FindParameterFiles( void );


// DVI datei inz. ge�ndert?
BOOL CALLBACK EnumCheckAll( HWND hwnd, LPARAM flags );


// COMMON-Dialog-Variablen
PRINTDLG PDlg;
CHOOSEFONT CFont;
LOGFONT	lf;

// globale Variablen
char szFrameClass [] = "FrameDVI" ;
char szBmpClass [] = "ChildDVI" ;
char szHilfedatei[256];
char szTempStr[256];

// F�r "zuf�llige Clipboardnamen ...
BYTE ClipBoardNumber = 0;
BOOL fit_window_to_size = 1;

HINSTANCE hInst;
HANDLE hSnomIcon;
HACCEL hAccel;
HMENU hMenuDVI, hMenuDVIWindow;

HWND hwndFrame, hwndClient, hwndInfo, hwndHilf, hwndToolbar;

#pragma argsused
int PASCAL WinMain( HANDLE hInstance, HANDLE hPrevInstance, LPSTR pCmdLine, int nCmdShow )
{
	// Zur initialisierung ...
	CLIENTCREATESTRUCT clientcreate;
	DWORD dwVersion;
	MSG msg ;
	WNDCLASS wndclass;
	hInst = hInstance;

	if( !hPrevInstance ) {
		// Fensterklasse f�r das Rahmenfenster
		wndclass.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
		wndclass.lpfnWndProc   = FrameWndProc;
		wndclass.cbClsExtra    = 0;
		wndclass.cbWndExtra    = 4;
		wndclass.hInstance     = hInst;
		wndclass.hIcon         = LoadIcon( hInst, "DVIIcon" );
		wndclass.hCursor       = LoadCursor( NULL, IDC_ARROW );
		wndclass.hbrBackground = (HBRUSH)( COLOR_APPWORKSPACE + 1 );
		wndclass.lpszMenuName  = NULL;
		wndclass.lpszClassName = szFrameClass;
		RegisterClass( &wndclass );

		// Fensterklasse f�r Bitmap-Dokumentenfesnter
		wndclass.style         = CS_HREDRAW | CS_VREDRAW | CS_PARENTDC;
		wndclass.lpfnWndProc   = DVIWndProc ;
		wndclass.cbClsExtra    = 0;
		wndclass.cbWndExtra    = sizeof( DVI_DOC* );
		wndclass.hInstance     = hInstance ;
		// Windows95 braucht Ikonen
		dwVersion = GetVersion();
		if( LOBYTE( LOWORD( dwVersion ) ) >= 3 ) {
			wndclass.hIcon       = LoadIcon( hInstance, "DVIIconDoc" );
		}
		else {
			wndclass.hIcon       = NULL;
		}
		wndclass.hCursor       = LoadCursor( NULL, IDC_ARROW ) ;
		wndclass.hbrBackground = GetStockObject( WHITE_BRUSH ) ;
		wndclass.lpszMenuName  = NULL ;
		wndclass.lpszClassName = szBmpClass ;
		RegisterClass( &wndclass ) ;

		// Fensterklasse f�r selbstdefiniertes Objekt "Wechselknopf" definieren ..
		wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
		wndclass.lpfnWndProc   = WechselknopfWndProc ;
		wndclass.cbClsExtra    = 0;
		wndclass.cbWndExtra    = 0;
		wndclass.hInstance     = hInstance ;
		wndclass.hIcon         = NULL;
		wndclass.hCursor       = LoadCursor( NULL, IDC_ARROW ) ;
		wndclass.hbrBackground = COLOR_WINDOW+1;
		wndclass.lpszMenuName  = NULL ;
		wndclass.lpszClassName = (LPSTR)"Wechselknopf";
		RegisterClass( &wndclass ) ;

		// Drucker initialisieren
		PDlg.lStructSize = sizeof( PRINTDLG );
		PDlg.hwndOwner = NULL;
		PDlg.hDevMode = NULL;
		PDlg.hDevNames = NULL;
		PDlg.Flags = PD_RETURNDEFAULT;
		PrintDlg( &PDlg );

		CFont.lStructSize = sizeof( CHOOSEFONT );
		CFont.hwndOwner = NULL;
		CFont.lpLogFont = &lf;
		CFont.Flags = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS | CF_ANSIONLY; // | CF_NOSTYLESEL;

		// Vern�nftig Initialisieren
		lstrcpy( lf.lfFaceName, "Arial" );
		lf.lfHeight = -12;
		lf.lfWeight = FW_DONTCARE;
		lf.lfOutPrecision = OUT_TT_PRECIS;
		lf.lfClipPrecision = CLIP_STROKE_PRECIS;
		lf.lfQuality = PROOF_QUALITY;
	}

	// Name der Hilfedatei finden
//	MakeHelpFileName( hInst, szHilfedatei, "DVI" );

#if 0
	// Man arbeitet nicht mehr ohne 3D
	// (obsolete for Win9x)
	Ctl3dRegister( hInst );
	Ctl3dAutoSubclass( hInst );
#endif

	// die zwei Handles f�r die Men�s
	hMenuDVI = LoadMenu( hInst, "MenuDVI" ) ;
	hMenuDVIWindow = GetSubMenu( hMenuDVI, BITMAP_MENU_POS ) ;

	// Tabelle mit Abk�rzungsbefehlen laden
	hAccel = LoadAccelerators( hInst, "AccMenuDVI" );

	// Rahmenfenster erzeugen
	hwndFrame = CreateWindowEx( WS_EX_ACCEPTFILES, szFrameClass, "DVI for Windows 0.2",
	                            WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
	                            CW_USEDEFAULT, CW_USEDEFAULT,
	                            CW_USEDEFAULT, CW_USEDEFAULT,
	                            NULL, hMenuDVI, hInst, NULL ) ;
	DragAcceptFiles( hwndFrame, TRUE );
#ifdef _WIN32
	hwndToolbar = CreateToolbarEx( hwndFrame, WS_CHILD|WS_VISIBLE|TBSTYLE_TOOLTIPS, ID_TOOLBAR, iMaxTool, hInst, TOOLBARIMG, pToolbarButtons, iMaxTool, 16, 16, 16, 16, sizeof( TBBUTTON ) );
#elif defined( __WIN32__ )
	hwndToolbar = CreateToolbar( hwndFrame, WS_CHILD|WS_BORDER|WS_VISIBLE|TBSTYLE_TOOLTIPS, ID_TOOLBAR, iMaxTool, hInst, TOOLBARIMG, pToolbarButtons, iMaxTool );
#endif
	SendMessage( hwndToolbar, TB_ENABLEBUTTON, MDDRUCKE, FALSE );
	SendMessage( hwndToolbar, TB_ENABLEBUTTON, MACOPYPAGE, FALSE );
	// StatusBar
	hwndInfo = CreateStatusWindow( WS_CHILD|WS_BORDER|WS_VISIBLE, NULL, hwndFrame, ID_STATUSBAR );

	// und die MDI-Fenster anlegen ...
	clientcreate.hWindowMenu  = hMenuDVIWindow;
	clientcreate.idFirstChild = IDM_FIRSTCHILD;
	hwndClient = CreateWindow( "MDICLIENT", "Client",
	                           WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL,
	                           0, 0, 0, 0, hwndFrame, (HMENU)19, hInst,
	                           (LPSTR)&clientcreate );
	ShowWindow( hwndFrame, nCmdShow );
	UpdateWindow( hwndFrame ) ;
	UpdateMenu( NULL );

	if( strlen( pCmdLine ) > 0 ) {
		MDICREATESTRUCT mdicreate;
		char *dd_argv[32], *pDatStr, *c, datei[256];
		int argc, gefunden;

#if 0
		MessageBox( hwndFrame, pCmdLine, NULL, MB_OK );
#endif
		argc = 1;
		dd_argv[argc] = strtok( (char*)pCmdLine, " " );
		if( dd_argv[argc][0] != '-' ) {
			pDatStr = dd_argv[argc];
		}
		else {
			argc++;
		}
		while( NULL != ( dd_argv[argc] = strtok( NULL, " " ) ) ) {
			if( dd_argv[argc][0] != '-' ) {
				pDatStr = dd_argv[argc];
			}
			else {
				argc++;
			}
		}

		gefunden = SearchPath( szTempStr, pDatStr, NULL, 256, datei, &c );       // Es darf der aktuelle Pfad noch nicht ge�ndert sein!
		FindParameterFiles();

		if( argc > 1 ) {
			process_cmd( argc, dd_argv, hwndFrame );
		}

		if( gefunden ) {
			mdicreate.szClass = (LPSTR)szBmpClass;
			mdicreate.szTitle = datei;
			mdicreate.hOwner  = hInst;
			mdicreate.x       = CW_USEDEFAULT;
			mdicreate.y       = CW_USEDEFAULT;
			mdicreate.cx      = CW_USEDEFAULT;
			mdicreate.cy      = CW_USEDEFAULT;
			mdicreate.style   = WS_CHILD|WS_BORDER;
			mdicreate.lParam  = (LONG)datei;
			SendMessage( hwndClient, WM_MDICREATE, 0, (LPARAM)(LPMDICREATESTRUCT)&mdicreate );
		}
	}
	else {
		FindParameterFiles();
	}


	// f�r MDI ver�nderte Ereignis-Warteschleife
	while( GetMessage( &msg, NULL, 0, 0 ) ) {
		if(  //(hModeLess==NULL  ||  !IsDialogMessage(hModeLess,&msg))  &&
		        !TranslateMDISysAccel( hwndClient, &msg )  &&
		        !TranslateAccelerator( hwndFrame, hAccel, &msg ) ) {
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		} // Aufr�umen der momentan nicht eingesetzten Men�s
	}
//	Ctl3dUnregister(hInst); // (obsolete for win9x)
	DestroyMenu( hMenuDVI ) ;
	return ( msg.wParam );
}


// 10.4.98


// String aus Resource
LPSTR GetStringRsc( UINT h )
{
	static char strBuffer[512];
	int iLen = LoadString( hInst, h, strBuffer, 512 );
	if( iLen > 0 ) {
		return ( strBuffer );
	}
	return ( NULL );
}


// Parameterdatei(en) finden
void FindParameterFiles( void )
{
	WIN32_FIND_DATA	dta;
	HANDLE ff;
	BYTE *c;
	WORD count = MOCNF_0;

	init_parameter();
	SearchPath( NULL, "dvi.cnf", NULL, 256, PARA_DAT, &c );
	read_parameter_datei( PARA_DAT );
	lstrcpy( c, "*.cnf" );
	if( ( ff = FindFirstFile( PARA_DAT, &dta ) ) != INVALID_HANDLE_VALUE ) {
		AppendMenu( GetSubMenu( hMenuDVI, CNF_MENU_POS ), MF_SEPARATOR, 0, 0 );
		do {
			AppendMenu( GetSubMenu( hMenuDVI, CNF_MENU_POS ), MF_STRING, count++, dta.cFileName );
		} while( FindNextFile( ff, &dta ) );
		FindClose( ff );
	}
}


/* Verwaltet das Init-Men� */
long PASCAL FrameWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
	FARPROC lpfnEnum;
	HWND hwndChild;
	char *datei;

	switch( message ) {
		case WM_CREATE:          // Client-Fenster erzeugen
			return ( 0 ) ;

		case WM_INITMENU:
			//  Clipboardstatus evt. �ndern
			break;

		case WM_SIZE:
			// N�tig, sonst wird das Client-Fenster auf volle Gr��e gebracht und verdeckt den Toolbar
			if( hwnd == hwndFrame )	{
				int y, dh, cx, cy;
				RECT xywh;

				SendMessage( hwndToolbar, WM_SIZE, wParam, lParam );
				SendMessage( hwndInfo, WM_SIZE, wParam, lParam );
				cx = LOWORD( lParam );
				cy = HIWORD( lParam );
				GetWindowRect( hwndInfo, &xywh );
				dh = xywh.bottom-xywh.top;
				GetWindowRect( hwndToolbar, &xywh );
				y = xywh.bottom-xywh.top;
				dh += y;
				SetWindowPos( hwndClient, NULL, 0, y, cx, cy-dh, SWP_NOZORDER );
				return ( 0 );
			}
			break;

		// Tooltips (hilfetexte)
		case WM_NOTIFY:
		{
			LPNMTTDISPINFO pTTText = (LPNMTTDISPINFO)lParam;

			if( pTTText->hdr.code == TTN_GETDISPINFO ) {
				pTTText->lpszText = GetStringRsc( pTTText->hdr.idFrom );
			}
			break;
		}

		case WM_DROPFILES:
		{
			MDICREATESTRUCT mdicreate;
			SWORD i, max;

			max = DragQueryFile( (HDROP)wParam, -1, datei, 256 );
			for( i = 0;  i < max;  i++ ) {
				datei = GlobalAlloc( GMEM_SHARE, 256 );
				DragQueryFile( (HDROP)wParam, i, datei, 256 );
				mdicreate.szClass = (LPSTR)szBmpClass;
				mdicreate.szTitle = datei;
				mdicreate.hOwner  = hInst;
				mdicreate.x       = CW_USEDEFAULT;
				mdicreate.y       = CW_USEDEFAULT;
				mdicreate.cx      = CW_USEDEFAULT;
				mdicreate.cy      = CW_USEDEFAULT;
				mdicreate.style   = WS_CHILD|WS_BORDER;
				mdicreate.lParam  = (LONG)datei;
				SendMessage( hwndClient, WM_MDICREATE, 0, (LPARAM)(LPMDICREATESTRUCT) &mdicreate ) ;
			}
			DragFinish( (HDROP)wParam );
			break;
		}

		case WM_ACTIVATE:
			// Testen, ob neuere Datei
			EnumChildWindows( hwndClient, EnumCheckAll, 0  );
			break;


		case WM_COMMAND:
		{
			switch( GET_WM_COMMAND_ID( wParam, lParam ) ) {
				case MDOPEN:
					datei = GlobalAlloc( GMEM_SHARE|GMEM_ZEROINIT, 256 );
					if( CMUFileOpen( hwnd, "DVI-Datei laden", datei, "DVI-Dateien\0*.dvi\0" ) ) {
						MDICREATESTRUCT mdicreate;
						mdicreate.szClass = (LPSTR)szBmpClass ;
						mdicreate.szTitle = datei;
						mdicreate.hOwner  = hInst;
						mdicreate.x       = CW_USEDEFAULT;
						mdicreate.y       = CW_USEDEFAULT;
						mdicreate.cx      = CW_USEDEFAULT;
						mdicreate.cy      = CW_USEDEFAULT;
						mdicreate.style   = WS_CHILD|WS_BORDER|WS_MAXIMIZE;
						mdicreate.lParam  = (LONG)(LPSTR)datei;
						SendMessage( hwndClient, WM_MDICREATE, 0, (LPARAM)(LPMDICREATESTRUCT) &mdicreate ) ;
					}
					else {
						GlobalFree( datei );
					}
					break;

				case MHABOUT:
					DialogBox( hInst, "AboutDialog", hwnd, StdDialog );
					break;

				case MAFIT:
					if( GetMenuState( hMenuDVI, wParam, 0 )&MF_CHECKED ) {
						CheckMenuItem( hMenuDVI, MAFIT, MF_UNCHECKED );
						fit_window_to_size = 0;
					}
					else {
						CheckMenuItem( hMenuDVI, MAFIT, MF_CHECKED );
						fit_window_to_size = 1;
					}
					break;

				case MDSETUP:
					PDlg.hwndOwner = hwndFrame;
					PDlg.Flags = PD_PRINTSETUP;
					PrintDlg( &PDlg );
					break;

				case MOTEX:
					DialogBox( hInst, MAKEINTRESOURCE( IDF_SPECIAL ), hwnd, SpecialDialog );
					break;

				case MOSONST:
					DialogBox( hInst, MAKEINTRESOURCE( DVIOPTIONEN ), hwnd, ExSetupDialog );
					break;

				case MORAND:
					DialogBox( hInst, "RandDialog", hwnd, RandDialog );
					break;

				case MALAYOUT:
					DialogBox( hInst, "LayoutSetup", hwnd, LayoutSetup );
					break;

				case MOLOAD:
					if( CMUFileOpen( hwnd, "CNF-Datei laden", PARA_DAT, "CNF-Dateien (*.cnf)\0*.cnf\0" ) ) {
						read_parameter_datei( PARA_DAT );
					}
					break;

				case MOSAVE:
					if( CMUFileSave( hwnd, "CNF-Datei sichern", PARA_DAT, "CNF-Dateien (*.cnf)\0*.cnf\0", NULL ) ) {
						write_parameter_datei( PARA_DAT );
					}
					break;

				// Anordnung der Dokumentenfenster
				case IDM_TILE:
					SendMessage( hwndClient, WM_MDITILE, 0, 0L ) ;
					return ( 0 ) ;

				case IDM_CASCADE:
					SendMessage( hwndClient, WM_MDICASCADE, 0, 0L ) ;
					return ( 0 ) ;

				case IDM_ARRANGE:
					SendMessage( hwndClient, WM_MDIICONARRANGE, 0, 0L ) ;
					return ( 0 ) ;

				case MDQUIT:           // Programm beenden
				case IDM_CLOSEALL:     // Schlie�en aller Dokumentenfenster
					lpfnEnum = MakeProcInstance( (FARPROC) CloseEnumProc, hInst ) ;
					EnumChildWindows( hwndClient, lpfnEnum, 0L ) ;
					DestroyWindow( hwndFrame );
					return ( 0 ) ;

#if 0
				case IDM_HILFESUCHEN:
					WinHelp( hwndFrame, szHilfedatei, HELP_PARTIALKEY, 0L );
					break;

				case IDM_HILFEINHALT:
					WinHelp( hwndFrame, szHilfedatei, HELP_INDEX, 0L );
					break;

#endif
				default:            // Weitergabe an aktives Dokumentenf.
					hwndChild = (HANDLE)SendMessage( hwndClient, WM_MDIGETACTIVE, 0, 0L );
					if( IsWindow( hwndChild ) ) {
						SendMessage( hwndChild, WM_COMMAND, wParam, lParam ) ;
					}
					break ;        // und danach an DefFrameProc
			}
			break ;
		}

#if 0
		case WM_QUERYENDSESSION:
		case WM_CLOSE:                     // alle Dokumentenfenster schlie�en
			SendMessage( hwnd, WM_COMMAND, IDM_CLOSEALL, 0L ) ;
			if( NULL != GetWindow( hwndClient, GW_CHILD ) ) {
				return ( 0 ) ;
			}
			DestroyWindow( hwnd );
			break ; // -> weiter mit DefFrameProc
#endif

		case WM_DESTROY:
		{
			DragAcceptFiles( hwndFrame, FALSE );
			PostQuitMessage( 0 ) ;
			return ( 0 ) ;
		}
	}
	// Weitergabe an DefFrameProc (ersetzt DefWindowProc)
	return ( DefFrameProc( hwnd, hwndClient, message, wParam, lParam ) );
}


#pragma argsused
BOOL PASCAL CloseEnumProc( HWND hwnd, LONG lParam )
{
	if( GetWindow( hwnd, GW_OWNER ) ) {       // Client-Fenster?
		return ( 1 );              // ja - nicht abbauen!
	}
	// Botschaft an das Client-Fenster: Dokument zur�ck auf Originalgr��e
	SendMessage( GetParent( hwnd ), WM_MDIRESTORE, (WPARAM)hwnd, 0L ) ;

	// Botschaft an das Dokumentenfenster: Schlie�en OK?
	if( !SendMessage( hwnd, WM_QUERYENDSESSION, 0, 0L ) ) {
		return ( 1 );
	}

	// OK. Botschaft an das Client-Fenster: Dokumentenfenster abbauen
	SendMessage( GetParent( hwnd ), WM_MDIDESTROY, (WPARAM)hwnd, 0L ) ;
	return ( 1 );
}


//**** Callback f�r das evt. Neuzeichnen der Fenster
BOOL CALLBACK EnumCheckAll( HWND hwnd, LPARAM flags )
{
	DVI_DOC *doc = (DVI_DOC*)GetWindowLong( hwnd, 0 );
	if( doc != NULL  &&  ( doc->ft.dwLowDateTime != 0  ||  doc->ft.dwLowDateTime != 0 ) ) {
		// Testen, ob Datei noch aktuell!
		FILETIME fakt;
		HANDLE hakt = CreateFile( (LPCSTR)doc->datei, GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );

		if( hakt != INVALID_HANDLE_VALUE ) {
			GetFileTime( hakt, NULL, NULL, &fakt );
			CloseHandle( hakt );
			if( CompareFileTime( &( doc->ft ), &fakt ) != 0 ) {
				PostMessage( hwnd, WM_COMMAND, MDNEULES, 0 );
			}
		}
	}
	return ( TRUE );
}
// 20.10.99


/*****************************************************************************************/
long PASCAL DVIWndProc( HWND hwnd, UINT message, UINT wParam, LONG lParam )
{
	DVI_DOC	*doc;
	LONG i;

	doc = (DVI_DOC*)GetWindowLong( hwnd, 0 );
	switch( message ) {
		case WM_CREATE:
		{
			LONG lPtr = ( ( (LPMDICREATESTRUCT)( (LPCREATESTRUCT)lParam )->lpCreateParams )->lParam );

			doc = (DVI_DOC*)Malloc( sizeof( DVI_DOC ) );
			strcpy( doc->datei, (LPSTR)lPtr );
			GlobalFree( (HGLOBAL)lPtr );
			init_treiber( doc );
			doc->status.reading = TRUE;
			doc->wh = hwnd;
			SetWindowLong( hwnd, 0, (LONG)doc );
			if(  !open_doc( doc, 0 )  ) {
				DestroyWindow( hwnd );
			}
			doc->status.reading = FALSE;
		} // WM_CREATE
			return ( 0 );

		case WM_SIZE:
		case WM_RECALC_SLIDER:
			if( doc  &&  doc->seiten != NULL  &&  doc->seiten[doc->dseite] != NULL ) {
				SCROLLINFO si;
				WORD cx = LOWORD( lParam );
				WORD cy = HIWORD( lParam );
				BOOL vscroll = cy*doc->status.vfaktor < doc->seiten[doc->dseite]->hoehe;
				WORD w = (WORD)( doc->seiten[doc->dseite]->weite+GetSystemMetrics( SM_CXVSCROLL )*vscroll );
				BOOL hscroll = cx*doc->status.hfaktor < w;

				if( wParam == -1  &&  lParam == -1 ) {
					if( fit_window_to_size  &&  IsZoomed( hwnd ) ) {
						// maybe maximize => first get requested size
						RECT outxywh, xywh;
						int toolbar_height, info_height = 0;
						GetWindowRect( hwndToolbar, &xywh );
						toolbar_height = xywh.bottom-xywh.top;
						GetWindowRect( hwndInfo, &xywh );
						info_height = xywh.bottom-xywh.top;
						GetWindowRect( hwndFrame, &xywh );
						GetClientRect( hwndFrame, &outxywh );
						outxywh.right = ( xywh.right-xywh.left-outxywh.right )+doc->status.vfaktor+doc->seiten[doc->dseite]->weite/doc->status.vfaktor;
						outxywh.bottom = ( xywh.bottom-xywh.top-outxywh.bottom )+doc->status.vfaktor+toolbar_height+info_height+doc->seiten[doc->dseite]->hoehe/doc->status.vfaktor;
						// now we have the window size => needs to determine the offset
						outxywh.top = xywh.top;
						if( outxywh.top+outxywh.bottom > GetSystemMetrics( SM_CYMAXIMIZED ) ) {
							outxywh.top = max( 0, GetSystemMetrics( SM_CYMAXIMIZED )-outxywh.bottom );
						}
						if( outxywh.top+outxywh.bottom > GetSystemMetrics( SM_CYMAXIMIZED ) ) {
							outxywh.bottom = GetSystemMetrics( SM_CYMAXIMIZED )-outxywh.top;
						}
						ShowScrollBar( hwnd, SB_VERT, FALSE );
						ShowScrollBar( hwnd, SB_HORZ, FALSE );
						outxywh.left = xywh.left;
						SetWindowPos( hwndFrame, 0, outxywh.left, outxywh.top, outxywh.right, outxywh.bottom, SWP_NOZORDER );
					}
					else {
						// no resize
						RECT xywh;
						GetClientRect( doc->wh, &xywh );
						SendMessage( doc->wh, WM_RECALC_SLIDER, 0, (UWORD)( xywh.right )|(ULONG)( xywh.bottom<<16l ) );
					}
					break;
				}

				ShowScrollBar( hwnd, SB_HORZ, hscroll );
				if( hscroll ) {
					si.cbSize = sizeof( SCROLLINFO );
					si.fMask = SIF_PAGE|SIF_RANGE;
					si.nMin = 0;
					si.nMax = w/doc->status.hfaktor;
					si.nPage = cx;
					SetScrollInfo( hwnd, SB_HORZ, &si, TRUE );
				}

				vscroll = cy*doc->status.vfaktor < doc->seiten[doc->dseite]->hoehe+GetSystemMetrics( SM_CYHSCROLL )*hscroll;
				ShowScrollBar( hwnd, SB_VERT, vscroll );
				if( vscroll ) {
					si.cbSize = sizeof( SCROLLINFO );
					si.fMask = SIF_PAGE|SIF_RANGE;
					si.nMin = 0;
					si.nMax = doc->seiten[doc->dseite]->hoehe/doc->status.vfaktor+3;
					si.nPage = cy;
					SetScrollInfo( hwnd, SB_VERT, &si, TRUE );
				}
			}
			else {
				ShowScrollBar( hwnd, SB_HORZ, FALSE );
				ShowScrollBar( hwnd, SB_VERT, FALSE );
			}
			break;

		// Horizontales Scrollen
		case WM_HSCROLL:
			if( doc  &&  doc->seiten != NULL  &&  doc->seiten[doc->seite] != NULL )	{
				long w = doc->seiten[doc->seite]->weite;
				long wOldX;
				long wOffset = GetScrollPos( hwnd, SB_HORZ );
				RECT xywh;

				wOldX = wOffset;
				GetClientRect( hwnd, &xywh );

				switch( LOWORD( wParam ) ) {
					case SB_LINEDOWN:
						wOffset += 32;
						break;

					case SB_LINEUP:
						wOffset -= 32;
						break;

					case SB_PAGEDOWN:
						wOffset += xywh.right*doc->status.hfaktor-16;
						break;

					case SB_PAGEUP:
						wOffset -= xywh.right*doc->status.hfaktor-16;
						break;

					case SB_BOTTOM:
						wOffset = w-xywh.right*doc->status.hfaktor-16;
						break;

					case SB_TOP:
						wOffset = 0;
						break;

					case SB_THUMBPOSITION:
					case SB_THUMBTRACK:
						wOffset = (ULONG)HIWORD( wParam );
						break;
				}
				if( wOffset < 0 ) {
					wOffset = 0;
				}
				SetScrollPos( hwnd, SB_HORZ, wOffset, TRUE );
				ScrollWindowEx( hwnd, wOldX-GetScrollPos( hwnd, SB_HORZ ), 0, NULL, NULL, NULL, NULL, SW_INVALIDATE|SW_ERASE );
			}
			break;

		// Vertikales Scrollen analog
		case WM_VSCROLL:
			if( doc  &&  doc->seiten != NULL  &&  doc->seiten[doc->seite] != NULL )	{
				long h = doc->seiten[doc->dseite]->hoehe;
				long wOldY;
				long wOffset = GetScrollPos( hwnd, SB_VERT );
				RECT xywh;

				wOldY = wOffset;
				GetClientRect( hwnd, &xywh );

				switch( LOWORD( wParam ) ) {
					case SB_LINEDOWN:
						wOffset += 32;
						break;

					case SB_LINEUP:
						wOffset -= 32;
						break;

					case SB_PAGEDOWN:
						wOffset += xywh.bottom-16;
						break;

					case SB_PAGEUP:
						wOffset -= xywh.bottom-16;
						break;

					case SB_BOTTOM:
						wOffset = h - xywh.bottom-16;
						break;

					case SB_TOP:
						wOffset = 0;
						break;

					case SB_THUMBPOSITION:
					case SB_THUMBTRACK:
#if 0
						wOffset = LOWORD( lParam );
#else
						// 32 Bit
						wOffset = HIWORD( wParam );
#endif
						break;
				}
				if( wOffset < 0 ) {
					wOffset = 0;
				}
				if( wOffset > h+10 ) {
					wOffset = h+20;
				}
				SetScrollPos( hwnd, SB_VERT, wOffset, TRUE );
				ScrollWindowEx( hwnd, 0, wOldY-GetScrollPos( hwnd, SB_VERT ), NULL, NULL, NULL, NULL, SW_INVALIDATE|SW_ERASE );
			}
			break;

		case WM_KEYDOWN:
		{
			UINT wMessage=0;
			WPARAM wScrollPar;

			switch( LOWORD( wParam ) ) {
				case VK_LEFT:
					wScrollPar = SB_LINEUP;
					wMessage = WM_HSCROLL;
					break;

				case VK_RIGHT:
					wScrollPar = SB_LINEDOWN;
					wMessage = WM_HSCROLL;
					break;

				case VK_HOME:
					wScrollPar = SB_TOP;
					wMessage = WM_HSCROLL;
					SendMessage( hwnd, wMessage, wScrollPar, 0 );
					wMessage = WM_VSCROLL;
					break;

				case VK_END:
					wScrollPar = SB_BOTTOM;
					wMessage = WM_HSCROLL;
					SendMessage( hwnd, wMessage, wScrollPar, 0 );
					wMessage = WM_VSCROLL;
					break;

				case VK_UP:
					wScrollPar = SB_LINEUP;
					wMessage = WM_VSCROLL;
					break;

				case VK_DOWN:
					wScrollPar = SB_LINEDOWN;
					wMessage = WM_VSCROLL;
					break;

				case VK_PRIOR:
					wScrollPar = MAPREV;
					wMessage = WM_COMMAND;
					break;

				case VK_NEXT:
					wScrollPar = MANEXT;
					wMessage = WM_COMMAND;
					break;

				case VK_ADD:
					wScrollPar = MAGROSS;
					wMessage = WM_COMMAND;
					break;

				case VK_SUBTRACT:
					wScrollPar = MAKLEIN;
					wMessage = WM_COMMAND;
					break;

				case ' ':
				{
					RECT xywh;
					int dh = GetScrollPos( doc->wh, SB_VERT );

					GetClientRect( hwnd, &xywh );

					if( doc->seiten[doc->dseite]->hoehe-10 > ( dh+xywh.bottom )*doc->status.vfaktor ) {
						wScrollPar = SB_PAGEDOWN;
						wMessage = WM_VSCROLL;
					}
					else {
						SendMessage( hwnd, WM_COMMAND, MANEXT, 0 );
						wScrollPar = SB_TOP;
						wMessage = WM_VSCROLL;
					}
					break;
				}
			}
			if(  wMessage  ) {
				SendMessage( hwnd, wMessage, wScrollPar, 0 );
			}
			break;
		}

		case WM_MOUSEWHEEL:
		{
			if( (short)HIWORD( wParam ) > 0 ) {
				SendMessage( hwnd, WM_VSCROLL, SB_LINEDOWN, 0 );
			}
			else if( (short)HIWORD( wParam ) < 0 ) {
				SendMessage( hwnd, WM_VSCROLL, SB_LINEUP, 0 );
			}
			break;
		}

		case WM_COMMAND:
			if( doc == NULL  ||  doc->seiten == NULL ) {
				break;
			}
			switch( GET_WM_COMMAND_ID( wParam, lParam ) ) {
				case MDNEULES:
				{
					DVI_DOC *new_doc = (DVI_DOC*)Malloc( sizeof( DVI_DOC ) );
					LONG new_page = doc->dseite;
					strcpy( new_doc->datei, doc->datei );
					FreeDoc( doc );
					doc = new_doc;
					init_treiber( doc );
					doc->status.reading = TRUE;
					doc->wh = hwnd;
					SetWindowLong( hwnd, 0, (LONG)doc );
					open_doc( doc, new_page );
					doc->status.reading = FALSE;
					break;
				}

				case MDSEITE:
				{
					PDlg.hwndOwner = hwndFrame;
					PDlg.hInstance = hInst;
					PDlg.Flags = PD_SHOWHELP|PD_RETURNDC;
					PDlg.hPrintTemplate = NULL;

					// Druckerabfrage und so
					if( PrintDlg( &PDlg ) ) {
						DOCINFO	di;
						double faktor;

						faktor = ( (int)( (double)GetDeviceCaps( PDlg.hDC, LOGPIXELSX )*10.0/(double)H_DPI+0.5 ) )/10.0;

						di.cbSize = sizeof( di );
						di.lpszDocName = doc->datei;
						di.lpszOutput = NULL;
#ifdef _WIN32
						di.lpszDatatype = "DVI32 (TeX)";
						di.fwType = 0;
#endif
						StartDoc( PDlg.hDC, &di );
						StartPage( PDlg.hDC );
						PrintDocPage( PDlg.hDC, doc, faktor );
						Message( doc, "Schicke Daten an den Drucker" );
						EndPage( PDlg.hDC );
						EndDoc( PDlg.hDC );
						DeleteDC( PDlg.hDC );
					}
					break;
				}

				case MDCLOSE:
					SendMessage( hwndClient, WM_MDIDESTROY, (WPARAM)hwnd, 0L ) ;
					return ( 0 ) ;

				case MAKLEIN:
					if( doc->status.hfaktor < 8 ) {
						RECT xywh;
						doc->status.hfaktor++;
						doc->status.vfaktor = doc->status.hfaktor;
						doc->page_in_display = 0x7FFFFFFFL;
						copy_to_display_buffer( doc );
						InvalidateRect( hwnd, NULL, FALSE );
						SendMessage( hwnd, WM_RECALC_SLIDER, -1, -1 );
					}
					break;

				case MAGROSS:
					if( doc->status.hfaktor > 1 ) {
						RECT xywh;
						doc->status.hfaktor--;
						doc->status.vfaktor = doc->status.hfaktor;
						doc->page_in_display = 0x7FFFFFFFL;
						copy_to_display_buffer( doc );
						InvalidateRect( hwnd, NULL, FALSE );
						SendMessage( hwnd, WM_RECALC_SLIDER, -1, -1 );
					}
					break;

				case MAGEHE:
					DialogBoxParam( hInst, MAKEINTRESOURCE( GEHE_ZU_SEITE ), hwnd, GotoDialog, (LPARAM)doc );
					break;

				case MANEXT:
					if( doc->status.layout ) {
						i = read_page( doc, doc->dseite+doc->blaetter_fkt );
					}
					else {
						i = read_page( doc, doc->dseite+1 );
					}
					doc->status.reading = FALSE;
					if( i ) {
						SendMessage( hwndClient, WM_MDIDESTROY, (WPARAM)hwnd, 0L ) ;
					}
					break;

				case MAPREV:
					if( doc->status.layout ) {
						i = read_page( doc, doc->dseite-doc->blaetter_fkt );
					}
					else {
						i = read_page( doc, doc->dseite-1 );
					}
					doc->status.reading = FALSE;
					if( i ) {
						SendMessage( hwndClient, WM_MDIDESTROY, (WPARAM)hwnd, 0L ) ;
					}
					break;

					// Ende Menubearbeitung
			}
			break;

		// M�gliche Maustastenbearbeitung ..
		case WM_LBUTTONUP:
			break;

		case WM_RBUTTONUP:
			break;

		case WM_MOUSEMOVE:
			break;

		case WM_RBUTTONDOWN:
			break;

		case WM_LBUTTONDOWN:
			break;

		case WM_PAINT:
			if( doc != NULL ) {
				RECT pCoord;

				UpdateMenu( doc );
				if( !IsIconic( hwnd ) ) {
					if( doc->display == NULL ) {
						copy_to_display_buffer( doc );
					}
					// Hier k�nnte durchaus eine Verkleinerung berechnet werden
					drawDoc( doc );
				}
			}
			return ( 0 );

		case WM_MDIACTIVATE:
			// Eingabefokus wechselt hierher?
			if( doc != NULL  &&  ( doc->ft.dwLowDateTime != 0  ||  doc->ft.dwLowDateTime != 0 ) ) {
				// Testen, ob Datei noch aktuell!
				FILETIME fakt;
				HANDLE hakt = CreateFile( (LPCSTR)doc->datei, GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );

				if( hakt != INVALID_HANDLE_VALUE ) {
					GetFileTime( hakt, NULL, NULL, &fakt );
					CloseHandle( hakt );
					if( CompareFileTime( &( doc->ft ), &fakt ) != 0 ) {
						DVI_DOC *new_doc = (DVI_DOC*)Malloc( sizeof( DVI_DOC ) );
						LONG new_page = doc->dseite;
						strcpy( new_doc->datei, doc->datei );
						FreeDoc( doc );
						doc = new_doc;
						init_treiber( doc );
						doc->status.reading = TRUE;
						doc->wh = hwnd;
						SetWindowLong( hwnd, 0, (LONG)doc );
						open_doc( doc, new_page );
						doc->status.reading = FALSE;
					}
				}
				UpdateMenu( doc );
			}
			return ( 0 ) ;

		case WM_QUERYENDSESSION:
		case WM_CLOSE:
		{
			WriteLN( doc, "Beende lesen..." );
			SendDlgItemMessage( hwndInfo, MANEXT, WM_ENABLE, FALSE, 0L );
			SendDlgItemMessage( hwndInfo, MAPREV, WM_ENABLE, FALSE, 0L );
			WriteLN( doc, "" );
			FreeDoc( doc );
			UpdateMenu( NULL );
			DrawMenuBar( hwndFrame ) ;
			break ; // -> weiter mit DefMDIChildProc
		}

		case WM_DESTROY:
			return ( 0 );
	}
	// Weitergabe an DefMDIChildProc (ersetzt DefWindowProc)
	return ( DefMDIChildProc( hwnd, message, wParam, lParam ) );
}
// 12.4.98


